package com.tec.cloud.notice.service;

import com.tec.cloud.notice.constant.ConfigType;
import com.tec.cloud.notice.vo.CertificateVO;
import com.tec.cloud.notice.vo.ConfigVO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.net.ssl.HttpsURLConnection;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.text.DateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;

@Component
public class CertificationJob {

    ConfigService configService;

    NoticeService noticeService;

    @Value("#{'${tec.notice.certification-notice-days:}'.empty ? null: '${tec.notice.certification-notice-days:}'.split(',')}")
//    @Value("#{'${tec.notice.certification-notice-days}'.split(',')}")
    private List<Integer> noticeDays;

    private final String messageFormat = "域名%s绑定的证书有效期截至到%s，目前还剩余%d天，请关注并及时处理。";

    public CertificationJob(ConfigService configService, NoticeService noticeService) {
        this.configService = configService;
        this.noticeService = noticeService;
    }

    @PostConstruct
    @Scheduled(cron = "0 0 10 * * ?")
    public void doNotice() throws IOException {

        if (CollectionUtils.isEmpty(noticeDays)) {
            return;
        }
        Collections.reverse(noticeDays);

        final List<ConfigVO> list = configService.list(ConfigType.CERTIFICATION_NOTICE.getCode());
        for (ConfigVO config : list) {
            try {
                if (Boolean.FALSE.equals(config.getNoticeFlag())) {
                    continue;
                }
                CertificateVO certificateVO = getNotAfterDate(config.getKey());
                for (Integer noticeDay : noticeDays) {
                    int notice = Math.min(Optional.ofNullable(config.getMinNoticeDay()).orElse(Integer.MAX_VALUE), noticeDay);
                    if (certificateVO.getExpireDate().compareTo(LocalDate.now().plusDays(notice)) < 0) {
                        noticeService.sendMarkDownMessage(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + "证书有效期到期提醒",
                                String.format(messageFormat, certificateVO.getDomain(), certificateVO.getExpireDate(), certificateVO.getExpireDate().toEpochDay() - LocalDate.now().toEpochDay()));
                        break;
                    }
                }

            } catch (RuntimeException e) {
                e.printStackTrace();
            }
        }
    }

    public CertificateVO getNotAfterDate(String url) throws IOException {
        URL destinationURL = new URL(url);
        HttpsURLConnection conn = (HttpsURLConnection) destinationURL.openConnection();
        conn.connect();
        Certificate[] certs = conn.getServerCertificates();
        for (Certificate cert : certs) {
            if (cert instanceof X509Certificate) {
                CertificateVO certificateVO = new CertificateVO();
                X509Certificate x509Certificate = ((X509Certificate) cert);
                // ( (X509Certificate) cert).checkValidity();
                final Date expireDate = x509Certificate.getNotAfter();
                Instant instant = expireDate.toInstant();
                ZoneId zoneId = ZoneId.ofOffset("UTC", ZoneOffset.UTC);
                // atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。
                LocalDate expireLocalDate = instant.atZone(zoneId).toLocalDate();
                certificateVO.setExpireDate(expireLocalDate);
                certificateVO.setDomain(x509Certificate.getSubjectDN().getName());
                return certificateVO;
            }
        }
        return null;
    }
}
